#ifndef Rectangle_First
#define Rectangle_First
#ifdef __GNUG__
#pragma interface
#endif

#include "Point.h"

//---- Rectangle ---------------------------------------------------------------

class Rectangle {
public:
	Rectangle();
	Rectangle(int x, int y, int w, int h);
	Rectangle(const Point &o, const Point &e);             
	Rectangle(const Point &e);
	Rectangle(int w, int h);
	Rectangle(const Rectangle&);

	int Width() const;
	int Height() const;
	int Left() const;
	int Top() const;
	
	Point NW() const;   Point N() const;       Point NE() const;
	Point W() const;    Point Center() const;  Point E() const;
	Point SW() const;   Point S() const;       Point SE() const;
	
	//         7|0|1
	//        -------
	//         6| |2
	//        -------
	//         5|4|3

	int PointToCorner(const Point &p) const;
	Point CornerToPoint(int n) const;

	friend Rectangle NormRect(const Point &p1, const Point &p2);                
	friend Rectangle BoundingBox(int, Point *pts, Point *npts= 0);
	int Area() const;

	Rectangle operator+ (const Point &p);
	Rectangle operator- (const Point &p);
	Rectangle operator+= (const Point &p);
	Rectangle operator-= (const Point &p);
	
	void Moveto(const Point &p);
	void Scaleby(const Point &p);
	Rectangle &Moveby(const Point &p);
	friend Rectangle Moveby(Rectangle r, const Point &p);

	friend bool operator== (const Rectangle &r1, const Rectangle &r2);
	friend bool operator!= (const Rectangle &r1, const Rectangle &r2);
	bool IsEmpty() const;
	bool IsNotEmpty() const;
	bool ContainsPoint(const Point &p) const;
	bool Intersects(const Rectangle &r) const;                               
	bool ContainsRect(const Rectangle &r) const;
	bool OvalContainsRect(const Rectangle &r) const;

	friend Rectangle Union(const Rectangle &r1, const Rectangle &r2);
	friend Rectangle Inter(Rectangle r1, const Rectangle &r2);
	friend int Difference(Rectangle *rp, const Rectangle &r1, const Rectangle &r2);
	Rectangle Intersect(const Rectangle &r);
	bool Clip(const Rectangle &r);
	static int Diff(Rectangle *rp, const Rectangle &r1, const Rectangle &r2);

	Rectangle Inset(const Point &p) const;
	Rectangle Expand(const Point &p) const;              
	Rectangle Merge(const Rectangle &r);

	Point Constrain(const Point &p);                
	friend Point ConstrainMoveRect(const Rectangle &r1, const Rectangle &r2, Point delta);
	Point AmountToTranslateWithin(const Rectangle &r);

	int PointToAngle(const Point &) const;
	Point AngleToPoint(int) const;
	Point OvalAngleToPoint(int) const;

	Rectangle WedgeBBox(int s, int e);

	friend OStream& operator<< (OStream &s, const Rectangle &r);
	friend IStream& operator>> (IStream &s, Rectangle &r);

	const char *AsString() const;

public:
	Point origin, extent;
};

SimpleMetaDef(Rectangle);

extern const Rectangle gRect0;

inline int Rectangle::Width() const
	{ return extent.x; }
inline int Rectangle::Height() const
	{ return extent.y; }
inline int Rectangle::Left() const
	{ return origin.x; }
inline int Rectangle::Top() const
	{ return origin.y; }       
inline Point Rectangle::Center() const
	{ return Point(origin.x+extent.x/2, origin.y+extent.y/2); }
inline Point Rectangle::NW() const
	{ return origin; }       
inline Point Rectangle::N() const
	{ return Point(origin.x+extent.x/2, origin.y); }
inline Point Rectangle::NE() const
	{ return Point(origin.x+extent.x-1, origin.y); }
inline Point Rectangle::E() const
	{ return Point(origin.x+extent.x-1, origin.y+extent.y/2); }      
inline Point Rectangle::SE() const
	{ return origin + extent - 1; }     
inline Point Rectangle::S() const
	{ return Point(origin.x+extent.x/2, origin.y+extent.y-1); }     
inline Point Rectangle::SW() const
	{ return Point(origin.x, origin.y+extent.y-1); }
inline Point Rectangle::W() const
	{ return Point(origin.x, origin.y+extent.y/2); }
inline int Rectangle::Area() const
	{ return extent.x * extent.y; }
inline Rectangle &Rectangle::Moveby(const Point &p)
	{ origin+= p; return *this; }         
inline Rectangle Rectangle::operator+= (const Point &p)
	{ origin+= p; return *this; }
inline Rectangle Rectangle::operator+ (const Point &p)
	{ return Rectangle(origin+p, extent); }  
inline Rectangle Rectangle::operator- (const Point &p)
	{ return Rectangle(origin-p, extent); }  
inline Rectangle Rectangle::operator-= (const Point &p)
	{ origin-= p; return *this; }
inline void Rectangle::Moveto(const Point &p)
	{ origin= p; }
inline void Rectangle::Scaleby(const Point &p)
	{ extent*= p; }
inline bool Rectangle::ContainsPoint(const Point &p) const
	{ return (bool) (p >= origin && p < origin + extent); }                       
inline bool Rectangle::IsEmpty() const
	{ return (bool) (extent.x <= 0 || extent.y <= 0); }       
inline bool Rectangle::IsNotEmpty() const
	{ return (bool) (extent.x > 0 && extent.y > 0); }
inline Rectangle Moveby(Rectangle r, const Point &p)
	{ r.origin+= p; return r; }
inline bool operator== (const Rectangle &r1, const Rectangle &r2)
	{ return (bool) (r1.origin == r2.origin && r1.extent == r2.extent); }
inline bool operator!= (const Rectangle &r1, const Rectangle &r2)
	{ return (bool) (r1.origin != r2.origin || r1.extent != r2.extent); }

#endif
